package org.hbgl.geoentity.admin.aspect;

import com.alibaba.fastjson.JSON;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.shiro.SecurityUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.hbgl.geoentity.admin.annotation.ExamineLog;
import org.hbgl.geoentity.admin.annotation.OperationLog;
import org.hbgl.geoentity.admin.shiro.LoginUser;
import org.hbgl.geoentity.admin.shiro.UserType;
import org.hbgl.geoentity.db.domain.GeUser;
import org.hbgl.geoentity.db.domain.LogExamine;
import org.hbgl.geoentity.db.service.GeUnitService;
import org.hbgl.geoentity.db.service.LogService;
import org.hbgl.geoentity.db.service.NodeService;
import org.hbgl.geoentity.db.vo.NodeApplyVo;
import org.hbgl.geoentity.db.vo.NodeVo;
import org.hbgl.geoentity.db.vo.UnitVo;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;

/**
 * 代码功能：
 * 开发日期：2022/4/18
 * 作者：蒋海仑
 * 联系方式：
 * 版本更迭说明：
 * 版权信息：河北广联信息技术有限公司
 */
@Aspect
@Component
@Order(1)
public class LogExamineAspect {
    private final Log logger = LogFactory.getLog(LogExamineAspect.class);

    @Resource
    private LogService logService;
    @Resource
    private GeUnitService unitService;
    @Resource
    private NodeService nodeService;

    /**
     * 此处的切点是注解的方式，也可以用包名的方式达到相同的效果
     * '@Pointcut("execution(* com.wwj.springboot.service.impl.*.*(..))")'
     */
    @Pointcut("@annotation(org.hbgl.geoentity.admin.annotation.ExamineLog)")
    private void operationLog() {
    }

    @Around("operationLog()")
    public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
        Object res = null;
        long time = System.currentTimeMillis();
        try {
            res = joinPoint.proceed();
            time = System.currentTimeMillis() - time;
            return res;
        } finally {
            try {
                // 方法执行完成后增加日志
                addExamineLog(joinPoint, res, time);
            } catch (Exception e) {
                logger.error("LogExamineAspect 操作失败", e);
            }
        }
    }

    private void addExamineLog(ProceedingJoinPoint joinPoint, Object res, long time) {
        LogExamine logExamine = new LogExamine();
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        ExamineLog annotation = signature.getMethod().getAnnotation(ExamineLog.class);
        if (annotation != null) {
            //获得登录用户信息
            LoginUser loginUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
            if (loginUser != null) {
                GeUser user = null;
                if (UserType.ADMIN.equals(annotation.userType())) {
                    user = loginUser.getAdminUser();
                } else if (UserType.UNIT.equals(annotation.userType())) {
                    user = loginUser.getUnitUser();
                }
                if (user != null) {
                    logExamine.setUnitId(user.getUnitId());
                    logExamine.setUserId(user.getId());
                    logExamine.setUsername(user.getUsername());
                    logExamine.setRealname(user.getRealname());
                }
            }

            logExamine.setOperationType(annotation.operationType().getValue());
            logExamine.setDetail(getDetail(signature.getParameterNames(), joinPoint.getArgs(), annotation));
        }
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        if (attributes != null) {
            HttpServletRequest request = attributes.getRequest();
            logExamine.setIpAddress(request.getRemoteAddr());
        }
        logExamine.setOperationTime(LocalDateTime.now());
        logExamine.setMethod(signature.getDeclaringTypeName() + "." + signature.getName());
        logExamine.setArgs(JSON.toJSONString(BaseAspect.getRequestParamsByProceedingJoinPoint(joinPoint)));
        Map result = JSON.parseObject(JSON.toJSONString(res), Map.class);
        if (result.containsKey("errno")) {
            logExamine.setState(Integer.parseInt(result.get("errno").toString()));
        }

        //4. 获取方法的参数
        Map<String, Object> requestParamsByProceedingJoinPoint = BaseAspect.getRequestParamsByProceedingJoinPoint(joinPoint);
        for (Map.Entry<String, Object> entry : requestParamsByProceedingJoinPoint.entrySet()) {
            // System.out.println("key= " + entry.getKey() + " and value= " + entry.getValue());
            if(entry.getKey().equals("examState")) {
                logExamine.setExamState(Integer.valueOf(entry.getValue().toString()));
            }
            if(entry.getKey().equals("remark")) {
                logExamine.setRemark((entry.getValue().toString()));
            }
            // System.out.println("切入方法的参数："+ entry.getKey() );
        }
        logService.add(logExamine);
    }

    /**
     * 对当前登录用户和占位符处理
     *
     * @param argNames   方法参数名称数组
     * @param args       方法参数数组
     * @param annotation 注解信息
     * @return 返回处理后的描述
     */
    private String getDetail(String[] argNames, Object[] args, ExamineLog annotation) {
        GeUser user = null;
        //获得登录用户信息
        LoginUser loginUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
        if (loginUser != null) {
            if (UserType.ADMIN.equals(annotation.userType())) {
                user = loginUser.getAdminUser();
            } else if (UserType.UNIT.equals(annotation.userType())) {
                user = loginUser.getUnitUser();
            }
        }
        if (user == null) {
            user = new GeUser();
            user.setUsername("未知用户");
        }
        String detail = annotation.detail();
        String detailName = "";
        Map<Object, Object> map = new HashMap<>(4);
        for (int i = 0; i < argNames.length; i++) {
            map.put(argNames[i], args[i]);
            if(argNames[i].equals("id")) {
                if(detail.equals("单位审核")) {
                    UnitVo unitVo = unitService.selectUnitTempById((Integer) args[i]);
                    if(unitVo == null) {
                        unitVo = unitService.selectUnitById((Integer) args[i]);
                    }
                    detailName = unitVo.getUnitName();
                }
                if(detail.equals("节点审核")) {
                    NodeApplyVo nodeApply = nodeService.findNodeApplyById((Integer) args[i]);
                    if(nodeApply == null) {
                        NodeVo node = nodeService.findNodeById((Integer) args[i]);
                        detailName = node.getNodeName();
                    }else {
                        detailName = nodeApply.getNodeName();
                    }

                }
            }
        }
        try {
            detail = "'" + user.getUsername() + "'=》" + annotation.detail() + " =》" + detailName;
            for (Map.Entry<Object, Object> entry : map.entrySet()) {
                Object k = entry.getKey();
                Object v = entry.getValue();
                //如果是文件对象
                if (v instanceof MultipartFile) {
                    MultipartFile file = (MultipartFile) v;
                    v = file.getOriginalFilename();  //获取文件名
                }
                detail = detail.replace("{{" + k + "}}", JSON.toJSONString(v));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return detail;
    }
}
